use sysinfo::{CpuExt, System, SystemExt};
use std::fmt;

/// 内存单位枚举
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MemoryUnit {
    Byte,
    KB,
    MB,
    GB,
    TB,
}

impl fmt::Display for MemoryUnit {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            MemoryUnit::Byte => write!(f, "B"),
            MemoryUnit::KB => write!(f, "KB"),
            MemoryUnit::MB => write!(f, "MB"),
            MemoryUnit::GB => write!(f, "GB"),
            MemoryUnit::TB => write!(f, "TB"),
        }
    }
}

/// 硬件信息结构体，用于获取系统硬件相关信息
#[derive(Debug)]
pub struct Hardware {
    sys: System,
}

impl Hardware {
    /// 创建新的Hardware实例并初始化系统信息
    pub fn new() -> Self {
        let mut sys = System::new();
        sys.refresh_all();
        Self { sys }
    }

    /// 刷新所有硬件信息
    pub fn refresh(&mut self) {
        self.sys.refresh_all();
    }

    /// 获取CPU核心数
    /// 
    /// 返回系统的物理CPU核心数量
    pub fn cpu_count(&self) -> usize {
        self.sys.cpus().len()
    }

    /// 获取系统总内存大小（以字节为单位）
    pub fn memory_total(&self) -> u64 {
        self.sys.total_memory()
    }

    /// 获取已使用的内存大小（以字节为单位）
    pub fn memory_used(&self) -> u64 {
        self.sys.used_memory()
    }

    /// 获取每个CPU核心的使用率
    /// 
    /// 返回一个包含所有CPU核心使用率的向量，使用率范围为0.0-100.0
    pub fn cpu_usage(&self) -> Vec<f32> {
        self.sys.cpus().iter().map(|cpu| cpu.cpu_usage()).collect()
    }

    /// 获取可用内存大小（以字节为单位）
    pub fn memory_available(&self) -> u64 {
        self.sys.total_memory() - self.sys.used_memory()
    }

    /// 将字节数转换为指定单位的值
    fn convert_memory_unit(&self, bytes: u64, unit: MemoryUnit) -> f64 {
        match unit {
            MemoryUnit::Byte => bytes as f64,
            MemoryUnit::KB => bytes as f64 / 1024.0,
            MemoryUnit::MB => bytes as f64 / (1024.0 * 1024.0),
            MemoryUnit::GB => bytes as f64 / (1024.0 * 1024.0 * 1024.0),
            MemoryUnit::TB => bytes as f64 / (1024.0 * 1024.0 * 1024.0 * 1024.0),
        }
    }

    /// 获取人类可读的内存总量
    pub fn memory_total_human(&self, unit: MemoryUnit) -> String {
        format!("{:.2} {}", self.convert_memory_unit(self.memory_total(), unit), unit)
    }

    /// 获取人类可读的已用内存
    pub fn memory_used_human(&self, unit: MemoryUnit) -> String {
        format!("{:.2} {}", self.convert_memory_unit(self.memory_used(), unit), unit)
    }

    /// 获取人类可读的可用内存
    pub fn memory_available_human(&self, unit: MemoryUnit) -> String {
        format!("{:.2} {}", self.convert_memory_unit(self.memory_available(), unit), unit)
    }

    /// 获取内存使用百分比
    pub fn memory_usage_percentage(&self) -> f64 {
        let total = self.memory_total() as f64;
        let used = self.memory_used() as f64;
        (used / total) * 100.0
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::time::Duration;
    use approx::assert_relative_eq;

    #[test]
    fn test_hardware_new() {
        let hardware = Hardware::new();
        assert!(hardware.cpu_count() > 0, "CPU数量应该大于0");
    }

    #[test]
    fn test_memory_info() {
        let hardware = Hardware::new();
        
        let total_memory = hardware.memory_total();
        let used_memory = hardware.memory_used();
        
        // 总内存应该大于0
        assert!(total_memory > 0, "总内存应该大于0");
        // 已用内存应该小于总内存
        assert!(used_memory <= total_memory, "已用内存不能大于总内存");
    }

    #[test]
    fn test_cpu_usage() {
        let hardware = Hardware::new();
        let cpu_usage = hardware.cpu_usage();
        
        // CPU使用率数组长度应该等于CPU数量
        assert_eq!(cpu_usage.len(), hardware.cpu_count());
        
        // CPU使用率应该在0-100之间
        for usage in cpu_usage {
            assert!((0.0..=100.0).contains(&usage), "CPU使用率应该在0-100之间");
        }
    }

    #[test]
    fn test_refresh() {
        let mut hardware = Hardware::new();
        
        // 强制进行一次完整的系统信息刷新
        hardware.refresh();
        let before_used = hardware.memory_used();
        
        // 创建一些内存压力
        let data: Vec<u8> = vec![0; 1024 * 1024]; // 分配1MB内存
        thread::sleep(Duration::from_millis(100));
        
        // 刷新并检查内存使用是否有变化
        hardware.refresh();
        let after_used = hardware.memory_used();
        
        // 保持数据存活直到测试结束
        assert!(!data.is_empty());
        
        // 验证内存信息
        assert!(before_used > 0, "内存使用量应该大于0");
        assert!(after_used > 0, "刷新后的内存使用量应该大于0");
    }

    #[test]
    fn test_memory_available() {
        let mut hardware = Hardware::new();
        
        // 强制进行一次完整的系统信息刷新
        hardware.refresh();
        
        let total = hardware.memory_total();
        let used = hardware.memory_used();
        let available = hardware.memory_available();
        
        println!("Total memory: {} bytes", total);
        println!("Used memory: {} bytes", used);
        println!("Available memory: {} bytes", available);
        
        assert!(total > 0, "总内存应该大于0");
        assert!(used > 0, "已用内存应该大于0");
        assert!(available > 0, "可用内存应该大于0");
        assert!(used + available == total, "已用内存+可用内存应该等于总内存");
    }

    #[test]
    fn test_memory_units_conversion() {
        let hardware = Hardware::new();
        
        // 创建一个固定大小的测试值：1GB + 100MB
        let test_bytes = 1024 * 1024 * 1024 + 100 * 1024 * 1024;
        
        // 使用 approx crate 进行近似比较
        assert_relative_eq!(
            hardware.convert_memory_unit(test_bytes, MemoryUnit::GB),
            1.0975341796875,
            epsilon = 0.001
        );
        assert_relative_eq!(
            hardware.convert_memory_unit(test_bytes, MemoryUnit::MB),
            1124.0,
            epsilon = 0.1
        );
        assert_relative_eq!(
            hardware.convert_memory_unit(test_bytes, MemoryUnit::KB),
            1124.0 * 1024.0,
            epsilon = 100.0
        );
    }

    #[test]
    fn test_memory_human_readable() {
        let hardware = Hardware::new();
        
        // 测试所有内存相关的human readable方法
        let total = hardware.memory_total_human(MemoryUnit::GB);
        let used = hardware.memory_used_human(MemoryUnit::MB);
        let available = hardware.memory_available_human(MemoryUnit::GB);
        
        // 验证格式是否正确
        assert!(total.ends_with(" GB"), "总内存应该以GB为单位");
        assert!(used.ends_with(" MB"), "已用内存应该以MB为单位");
        assert!(available.ends_with(" GB"), "可用内存应该以GB为单位");
        
        // 验证数值是否可以解析
        let total_value = total.trim_end_matches(" GB").parse::<f64>();
        assert!(total_value.is_ok(), "应该能够解析内存值");
        assert!(total_value.unwrap() > 0.0, "总内存应该大于0");
    }

    #[test]
    fn test_memory_percentage() {
        let hardware = Hardware::new();
        let percentage = hardware.memory_usage_percentage();
        
        // 内存使用百分比应该在0-100之间
        assert!((0.0..=100.0).contains(&percentage), 
            "内存使用百分比应该在0-100之间，实际值: {}", percentage);
    }

    #[test]
    fn test_memory_units_display() {
        assert_eq!(MemoryUnit::Byte.to_string(), "B");
        assert_eq!(MemoryUnit::KB.to_string(), "KB");
        assert_eq!(MemoryUnit::MB.to_string(), "MB");
        assert_eq!(MemoryUnit::GB.to_string(), "GB");
        assert_eq!(MemoryUnit::TB.to_string(), "TB");
    }
} 